//============================================================================
// Copyright (C) 2009-2013 Brett R. Jones 
//
// Issued to public domain 2013
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================

#include "VxNetLib.h"
#include <VxUtilLib/VxSktUtil.h>
#include <memory.h>

#ifdef WIN_PLATFORM
	#define EINPROGRESS	WSAEWOULDBLOCK 
#else
	#include <fcntl.h>
#endif // WIN_PLATFORM


//============================================================================
//=== constructor ===//
VxSktConnectSimple::VxSktConnectSimple()
	: m_oSocket( INVALID_SOCKET )				// handle to socket
	, m_oLclIp()				// local ip address
	, m_oRmtIp()				// remote (peer) ip address
	//=== state vars ===//
	, m_bIsConnected(0)			// return true if is connected
	//=== user defined data ===//
	, m_u64UserData(0)
{
	// empty
}
//============================================================================
//=== destructor ===//
VxSktConnectSimple::~VxSktConnectSimple()
{
	CloseSkt( 99 );
}
//============================================================================
//! get the sockets peer connection ip address as host order U32
RCODE VxSktConnectSimple::GetRemoteIp(	VxInetAddress& u32RetIp,		// return ip
										U16 &u16RetPort )	// return port
{
	u32RetIp	= m_oRmtIp;
	u16RetPort	= m_oRmtIp.getPort();
	return 0;
}
//============================================================================
//! return true if is connected
BOOL VxSktConnectSimple::IsConnected( void )
{
	if( INVALID_SOCKET == m_oSocket )
	{
		m_bIsConnected = false;
		return false;
	}
	return m_bIsConnected;
}

//============================================================================
//! get remote ip as string
const char * VxSktConnectSimple::GetRemoteIp( void )
{
	return m_strLclIp.c_str();
}
//============================================================================
//! simpler version of GetRemoteIp returns ip as host order U32
RCODE VxSktConnectSimple::GetRemoteIp( VxInetAddress& u32RetIp )			// return ip
{
	u32RetIp	= m_oRmtIp;
	return 0;
}
//============================================================================	
//! used internally to get the remote ip address and set it in the vars
RCODE VxSktConnectSimple::DoGetRmtAddress( void )
{
	return VxSktCode::getRmtAddress( m_oSocket, m_oRmtIp );
}

//============================================================================
//! encrypt then send data using session crypto
RCODE VxSktConnectSimple::TxEncrypted(	const char *	pDataIn, 		// data to send
										int				iDataLen,		// length of data
										BOOL			bDisconnect )	// if true disconnect after send
{
	vx_assert( pDataIn );
	vx_assert( iDataLen );
	vx_assert( 0 == (iDataLen & 0x0f) );
	// make copy of data so data is not destroyed
	unsigned char * pu8Data = new unsigned char[ iDataLen ];
	memcpy( pu8Data, pDataIn, iDataLen );
	// encrypt
	RCODE rc =	m_oTxCrypto.Encrypt( pu8Data, iDataLen );
	if( 0 == rc )
	{
		// send
		rc = this->SendData( (char *)pu8Data, iDataLen );
	}
	if( rc )
	{
		log_msg( LOG_ERROR, "VxSktBase::TxEncrypted: error %d\n", rc );
	}
	delete pu8Data;
	if( bDisconnect )
	{
		VxSleep( 50 );
		CloseSkt();
	}
	return rc;
}


//============================================================================
//! connect to remote ip
SOCKET VxSktConnectSimple::ConnectTo(	const char *	pIpOrUrl,				// remote ip or url
										U16				u16Port,				// port to connect to
										int				iTimeoutMilliSeconds )	// milli seconds before connect attempt times out
{
	m_bIsConnected	= false;

	if( IsConnected() )
	{
		log_msg( 0, "VxSktConnectSimple::ConnectTo: connect attempt on allready connected socket\n" );
		vx_assert( false );
		return -1;
	}

	m_oSocket		= VxSktCode::ConnectTo( m_oLclIp, m_oRmtIp, pIpOrUrl, u16Port, iTimeoutMilliSeconds );
	if( INVALID_SOCKET != m_oSocket )
	{
		m_bIsConnected = true;
	}
	return m_oSocket;
}

//============================================================================
//! send data 
RCODE VxSktConnectSimple::SendData(	const char *	pData,					// data to send
									int				iDataLen,				// length of data
									int				iTimeoutSeconds )		// seconds before send attempt times out
{
	if( false == this->IsConnected() )
	{
		log_msg( 0, "VxSktConnectSimple::SendData: attempted send on disconnected socket\n" );
		return -1;
	}
	return VxSendSktData( m_oSocket, pData, iDataLen, iTimeoutSeconds );
}
		
//============================================================================
//! receive data.. if timeout is set then will keep trying till buffer is full or error or timeout expires
RCODE VxSktConnectSimple::RecieveData(	char *			pRetBuf,				// buffer to receive data into
										int				iBufLenIn,				// length of buffer
										int *			iRetBytesRecieved,		// number of bytes actually received
										int				iTimeoutMilliSeconds,	// milliseconds before receive attempt times out ( 0 = dont wait )
										BOOL			bAbortIfCrLfCrLf,		// if true then abort receive when \r\n\r\n is received
										BOOL *			pbRetGotCrLfCrLf )		// if received \r\n\r\n set to true
{
	return VxRecieveSktData( m_oSocket, pRetBuf, iBufLenIn, iRetBytesRecieved, iTimeoutMilliSeconds, bAbortIfCrLfCrLf, pbRetGotCrLfCrLf);
}

//============================================================================
//! close socket
void VxSktConnectSimple::CloseSkt( int iInstance )
{
	VxCloseSktNow( m_oSocket );
}
